home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / muds / pennmush.000 / pennmush-1.50-p8-linux.tar / pennmush / predicates.c < prev    next >
C/C++ Source or Header  |  1993-04-10  |  19KB  |  836 lines

  1. /* predicates.c */
  2.  
  3. #include "copyright.h"
  4.  
  5. /* Predicates for testing various conditions */
  6.  
  7. #include <stdio.h>
  8. #include <varargs.h>
  9. #include <ctype.h>
  10. #include <string.h>
  11. #include <sys/time.h>
  12.  
  13. #include "config.h"
  14. #include "externs.h"
  15. #include "db.h"
  16. #include "interface.h"
  17. #include "globals.h"
  18. #include "ansi.h"
  19.  
  20. extern int first_free;        /* free object list, from destroy.c */
  21.  
  22.  
  23. char *tprintf(va_alist)
  24. va_dcl    
  25. {
  26.   /* this is a generic function used to generate a format string */
  27.  
  28.   static char buff[BUFFER_LEN*2]; /* safety margin */
  29.   va_list args;
  30.   char *fmt;
  31.   
  32.   va_start(args);
  33.   fmt = va_arg(args, char *);
  34.   
  35.   (void)vsprintf(buff, fmt, args);
  36.   buff[BUFFER_LEN - 1] = '\0';
  37.   return (buff);
  38. }
  39.  
  40. int could_doit(player, thing)
  41.     dbref player;
  42.     dbref thing;
  43. {
  44.   /* lock evaluation -- determines if player passes lock on thing, for
  45.    * the purposes of picking up an object or moving through an exit
  46.    */
  47.  
  48.   if (Typeof(thing) != TYPE_ROOM && db[thing].location == NOTHING)
  49.     return 0;
  50.   return (eval_boolexp(player, db[thing].key, thing, 0, BASICLOCK));
  51. }
  52.  
  53. void did_it(player, thing, what, def, owhat, odef, awhat, loc)
  54.     dbref player;
  55.     dbref thing;
  56.     char *what;
  57.     char *def;
  58.     char *owhat;
  59.     char *odef;
  60.     char *awhat;
  61.     dbref loc;
  62. {
  63.   /* executes the @attr, @oattr, @aattr for a command - gives a message
  64.    * to the enactor and others in the room with the enactor, and executes
  65.    * an action.
  66.    */
  67.  
  68.   ATTR *d;
  69.   char *tbuf1;
  70.   char tbuf2[BUFFER_LEN];
  71.  
  72.   loc = (loc == NOTHING) ? db[player].location : loc;
  73.  
  74.   /* only give messages if the location is good */
  75.   if (GoodObject(loc)) {
  76.  
  77.     /* message to player */
  78.     if (what && *what) {
  79.       d = atr_get(thing, what);
  80.       if (d) {
  81.     strcpy(tbuf2,uncompress(d->value));
  82.     tbuf1 = exec(thing, player, 0, tbuf2);
  83.     notify(player, tbuf1);
  84.     free(tbuf1);
  85.       } else if (def && *def)
  86.     notify(player, def);
  87.     }
  88.     /* message to neighbors */
  89.     if (!Dark(player)) {
  90.       if (owhat && *owhat) {
  91.         d = atr_get(thing, owhat);
  92.         if (d) {
  93.       strcpy(tbuf2, uncompress(d->value));
  94.       tbuf1 = exec(thing, player, 0, tbuf2);
  95.       notify_except2(db[loc].contents, player, thing,
  96.              tprintf("%s %s", db[player].name, tbuf1));
  97.       free(tbuf1);
  98.     } else {
  99.       if (odef && *odef) {
  100.         notify_except2(db[loc].contents, player, thing, 
  101.                tprintf("%s %s", (int) db[player].name, 
  102.                    (int) odef));
  103.       }
  104.     }
  105.       }
  106.     }
  107.   }
  108.  
  109.   /* always do the action attribute if there is one (so things like
  110.    * rooms can @trigger) */
  111.   if (awhat && *awhat && (d = atr_get(thing, awhat))) {
  112.     ATTR *b;
  113.  
  114.     strcpy(tbuf2, uncompress(d->value));
  115.  
  116.     /* check if object has # of charges */
  117.     b = atr_get_noparent(thing, "CHARGES");
  118.  
  119.     if (!b) {
  120.       /* no charges set, just execute the action */
  121.       parse_que(thing, tbuf2, player);
  122.       return;
  123.     } else {
  124.       int num = atoi(b->value);
  125.       if (num) {
  126.     /* charges left, decrement and execute */
  127.     (void) atr_add(thing, "CHARGES", tprintf("%d", num - 1),
  128.                        db[b->creator].owner, NOTHING);
  129.     parse_que(thing, tbuf2, player);
  130.     return;
  131.       } else if (!(d = atr_get(thing, "RUNOUT")))
  132.     /* no charges left and no runout; do nothing */
  133.     return;
  134.       /* no charges left, execute runout */
  135.       strcpy(tbuf2, uncompress(d->value));
  136.       parse_que(thing, tbuf2, player);
  137.     }
  138.   }
  139. }
  140.  
  141. int can_see(player, thing, can_see_loc)
  142.     dbref player;
  143.     dbref thing;
  144.     int can_see_loc;
  145. {
  146.   /*
  147.    * 1) your own body isn't listed in a 'look' 2) exits aren't listed in a
  148.    * 'look' 3) unconnected (sleeping) players aren't listed in a 'look'
  149.    */
  150.   if (player == thing ||
  151.       Typeof(thing) == TYPE_EXIT ||
  152.       ((Typeof(thing) == TYPE_PLAYER) &&
  153.        !IS(thing, TYPE_PLAYER, PLAYER_CONNECT)))
  154.     return 0;
  155.  
  156.   /* if the room is lit, you can see any non-dark objects */
  157.   else if (can_see_loc)
  158.     return (!Dark(thing));
  159.  
  160.   /* otherwise room is dark and you can't see a thing */
  161.   else
  162.     return 0;
  163. }
  164.  
  165. int controls(who, what)
  166.     dbref who;
  167.     dbref what;
  168. {
  169.   /* Wizard controls everything 
  170.    * owners control their stuff
  171.    * something which is in the enterlock of a ZMO controls non-INHERIT
  172.    * and non-player objects.
  173.    * INHERIT checks between two objects are checked in the code for the
  174.    * specific function in question (do_trigger, do_set, etc.)
  175.    * Those who pass the enterlock of a ZoneMaster control his objects.
  176.    */
  177.  
  178.     if (!GoodObject(what))
  179.     return 0;
  180.  
  181.     if (Owns(who, what) || Wizard(who))
  182.     return 1;
  183.  
  184.     if ((Zone(what) != NOTHING) &&
  185.     (Typeof(what) != TYPE_PLAYER) && !(Flags(what) & INHERIT) &&
  186.     (eval_boolexp(who, Enterkey(Zone(what)), what, 0, ENTERLOCK)))
  187.     return 1;
  188.  
  189.     if (ZMaster(Owner(what)) &&
  190.     (eval_boolexp(who, Enterkey(Owner(what)), what, 0, ENTERLOCK)))
  191.     return 1;
  192.  
  193.     return 0;
  194. }
  195.  
  196. int can_pay_fees(who, pennies)
  197.     dbref who;
  198.     int pennies;
  199. {
  200.   /* does who have enough pennies to pay for something, and if something
  201.    * is being built, does who have enough quota? Wizards and royalty
  202.    * aren't subject to either, and immortals aren't subject to the former.
  203.    */
  204.  
  205. #ifdef QUOTA
  206.   int pay_quota();
  207. #endif /* QUOTA */
  208.   
  209.   /* don't do any checks if player is priv'ed */
  210.   if (NoPay(who))
  211.     return 1;
  212.  
  213.   /* can't charge till we've verified building quota */
  214.   if (Pennies(Owner(who)) < pennies) {
  215.     notify(who, tprintf("Sorry, you don't have enough %s.", MONIES));
  216.     return 0;
  217.   }
  218.  
  219.   /* check building quota */
  220. #ifdef QUOTA
  221.   if (!pay_quota(who, QUOTA_COST)) {
  222.     notify(who, "Sorry, your building quota has run out.");
  223.     return 0;
  224.   }
  225. #endif /* QUOTA */
  226.  
  227.   /* check database size -- EVERYONE is subject to this! */
  228. #ifdef BUILDING_LIMIT
  229.   if ((db_top >= DBTOP_MAX + 1) && (first_free == NOTHING)) {
  230.     notify(who, "Sorry, there is no more room in the database.");
  231.     return 0;
  232.   }
  233. #endif                /* BUILDING_LIMIT */
  234.  
  235.   /* charge */
  236.   payfor(who, pennies);
  237.  
  238.   return 1;
  239. }
  240.  
  241. void giveto(who, pennies)
  242.     dbref who;
  243.     dbref pennies;
  244. {
  245.   /* give who pennies */
  246.  
  247.   /* wizards and royalty don't need pennies */
  248.   if (NoPay(who))
  249.     return;
  250.  
  251.   who = Owner(who);
  252.   s_Pennies(who, Pennies(who) + pennies);
  253. }
  254.  
  255. int payfor(who, cost)
  256.     dbref who;
  257.     int cost;
  258. {
  259.   /* subtract cost from who's pennies */
  260.  
  261.   dbref tmp;
  262.   if (NoPay(who))
  263.     return 1;
  264.   else if ((tmp = Pennies(Owner(who))) >= cost) {
  265.     s_Pennies(Owner(who), tmp - cost);
  266.     return 1;
  267.   } else
  268.     return 0;
  269. }
  270.  
  271. #ifdef QUOTA
  272.  
  273. int get_current_quota(who)
  274.      dbref who;
  275. {
  276.   /* figure out a player's quota. Add the RQUOTA attribute if he doesn't
  277.    * have one already. This function returns the REMAINING quota, not
  278.    * the TOTAL limit.
  279.    */
  280.  
  281.   ATTR *a;
  282.   int i;
  283.   int limit;
  284.   int owned = 0;
  285.  
  286.   /* if he's got an RQUOTA attribute, his remaining quota is that */
  287.   a = atr_get_noparent(Owner(who), "RQUOTA");
  288.   if (a)
  289.     return (atoi(uncompress(a->value)));
  290.   
  291.   /* else, count up his objects. If he has less than the START_QUOTA,
  292.    * then his remaining quota is that minus his number of current objects.
  293.    * Otherwise, it's his current number of objects. Add the attribute
  294.    * if he doesn't have it.
  295.    */
  296.  
  297.   for (i = 0; i < db_top; i++)
  298.     if (Owner(i) == Owner(who))
  299.       owned++;
  300.   owned--;            /* don't count the player himself */
  301.  
  302.   if (owned <= atoi(START_QUOTA)) 
  303.     limit = atoi(START_QUOTA) - owned;
  304.   else 
  305.     limit = owned;
  306.  
  307.   atr_add(Owner(who), "RQUOTA", tprintf("%d", limit), GOD, NOTHING);
  308.  
  309.   return (limit);
  310. }
  311.  
  312.  
  313. void change_quota(who, payment)
  314.     dbref who;
  315.     int payment;
  316. {
  317.   /* add or subtract from quota */
  318.  
  319.   /* wizards and royalty don't need a quota */
  320.   if (NoPay(Owner(who)))
  321.     return;
  322.  
  323.   atr_add(Owner(who), "RQUOTA", 
  324.       tprintf("%d", get_current_quota(who) + payment),
  325.       GOD, NOTHING);
  326. }
  327.  
  328. int pay_quota(who, cost)
  329.     dbref who;
  330.     int cost;
  331. {
  332.   /* determine if we've got enough quota to pay for an object,
  333.    * and, if so, return true, and subtract from the quota.
  334.    */
  335.  
  336.   int curr;
  337.  
  338.   /* wizards and royalty don't need a quota */
  339.   if (NoPay(Owner(who)))
  340.     return 1;
  341.  
  342.   /* figure out how much we have, and if it's big enough */
  343.   curr = get_current_quota(who);
  344.  
  345.   if (curr - cost < 0)        /* not enough */
  346.     return 0;
  347.   
  348.   change_quota(who, - cost);
  349.  
  350.   return 1;
  351. }
  352. #endif /* QUOTA */
  353.  
  354. int name_wild_match(name, pattern)
  355.      const char *name, *pattern;
  356. {
  357.   /* quick wildcard match on name */
  358.  
  359.   if (*pattern == '\0')
  360.     return 0;
  361.   while (pattern && *pattern) {
  362.     switch (*pattern) {
  363.     case '*':
  364.       pattern++;
  365.       while ((*name) && (*name != '\0'))
  366.     name++;
  367.       break;
  368.     case '?':
  369.       pattern++;
  370.       name++;
  371.       break;
  372.     default:
  373.       if (UPCASE(*pattern) != UPCASE(*name))
  374.     return 0;
  375.       name++;
  376.       pattern++;
  377.     }
  378.   }
  379.   return 1;
  380. }
  381.  
  382.  
  383. int forbidden_name(name)
  384.      const char *name;
  385. {
  386.   /* checks to see if name is in the forbidden names file */
  387.  
  388.   char buf[BUFFER_LEN], *newlin, *ptr;
  389.   FILE *fp;
  390.  
  391.   fp = fopen(NAMES_FILE, "r");
  392.   while ((fp != NULL) && (!feof(fp))) {
  393.     fgets(buf, BUFFER_LEN, fp);
  394.     /* step on the newline */
  395.     if ((newlin = (char *) index(buf, '\n')) != NULL) *newlin = '\0';
  396.     ptr = buf;
  397.     if (!strcasecmp(name, ptr)) {
  398.       fclose(fp);
  399.       return 1;
  400.     }
  401.   }
  402.   fclose(fp);
  403.   return 0;
  404. }
  405.  
  406. int ok_name(name)
  407.     const char *name;
  408. {
  409.   /* is name valid for an object? */
  410.  
  411.   while(name && *name && isspace(*name)) name++;
  412.   return (name
  413.       && *name
  414.       && *name != LOOKUP_TOKEN
  415.       && *name != NUMBER_TOKEN
  416.       && *name != NOT_TOKEN
  417.       && !index(name, ARG_DELIMITER)
  418.       && !index(name, AND_TOKEN)
  419.       && !index(name, OR_TOKEN)
  420.       && strcasecmp(name, "me")
  421.       && strcasecmp(name, "home")
  422.       && strcasecmp(name, "here"));
  423. }
  424.  
  425. int ok_player_name(name)
  426.     const char *name;
  427. {
  428.   /* is name okay for a player? */
  429.  
  430.   const char *scan;
  431.   if (!ok_name(name) || forbidden_name(name) ||
  432.       strlen(name) > PLAYER_NAME_LIMIT)
  433.     return 0;
  434.  
  435.   for (scan = name; *scan; scan++) {
  436.     if (!(isprint(*scan) && !isspace(*scan))) {    /* was isgraph(*scan) */
  437.       return 0;
  438.     }
  439.   }
  440.  
  441.   return(lookup_player(name) == NOTHING);
  442. }
  443.  
  444. int ok_password(password)
  445.     const char *password;
  446. {
  447.   /* is password an acceptable password? */
  448.  
  449.   const char *scan;
  450.   if (*password == '\0')
  451.     return 0;
  452.  
  453.   for (scan = password; *scan; scan++) {
  454.     if (!(isprint(*scan) && !isspace(*scan))) {
  455.       return 0;
  456.     }
  457.   }
  458.  
  459.   return 1;
  460. }
  461.  
  462. void sstrcat(string, app)
  463.     char *string;
  464.     char *app;
  465. {
  466.   char *s;
  467.   char tbuf1[BUFFER_LEN];
  468.  
  469.   if ((strlen(app) + strlen(string)) >= BUFFER_LEN)
  470.     return;
  471.   sprintf(tbuf1, "%s", app);
  472.   for (s = tbuf1; *s; s++)
  473.     if ((*s == ',') || (*s == ';'))
  474.       *s = ' ';
  475.   strcat(string, tbuf1);
  476. }
  477.  
  478. /* for lack of better place the @switch code is here */
  479. void do_switch(player, exp, argv, cause, first)
  480.     dbref player;
  481.     char *exp;
  482.     char *argv[];
  483.     dbref cause;
  484.     int first;            /* 0, match all, 1, match first */
  485. {
  486.   int any = 0, a;
  487.   char *buff;
  488.  
  489.   if (!argv[1])
  490.     return;
  491.  
  492.   /* now try a wild card match of buff with stuff in coms */
  493.   for (a = 1; (a < (MAX_ARG - 1)) && argv[a] && argv[a + 1]; a += 2) {
  494.     /* eval expression */
  495.     buff = exec(player, cause, EV_STRIP | EV_FCHECK, argv[a]);
  496.  
  497.     /* check for a match */
  498.     if (local_wild_match(buff, exp)) {
  499.       if (first && any) {
  500.     /* terminate loop if only want first match */
  501.     free(buff);
  502.     break;
  503.       } else {
  504.     any = 1;
  505.     parse_que(player, argv[a + 1], cause);
  506.     free(buff);
  507.       }
  508.     } else {
  509.       free(buff);
  510.     }
  511.   }
  512.  
  513.   /* do default if nothing has been matched */
  514.   if ((a < MAX_ARG) && !any && argv[a])
  515.     parse_que(player, argv[a], cause);
  516. }
  517.  
  518. dbref parse_match_possessive(player, str)
  519.      dbref player;
  520.      char *str;
  521. {
  522.   char *box;            /* name of container */
  523.   char *obj;            /* name of object */
  524.   dbref loc;            /* dbref of container */
  525.   char name[BUFFER_LEN];    /* str would be destructively modified */
  526.  
  527.   strcpy(name, str);
  528.   box = name;
  529.  
  530.   /* check to see if we have an 's sequence */
  531.   if ((obj = (char *) index(name, '\'')) == NULL)
  532.     return NOTHING;
  533.   *obj++ = '\0';        /* terminate */
  534.   if ((*obj == NULL) || ((*obj != 's') && (*obj != 'S')))
  535.     return NOTHING;
  536.  
  537.   /* skip over the 's' and whitespace */
  538.   do {
  539.     obj++;
  540.   } while (isspace(*obj));
  541.  
  542.   /* we already have a terminating null, so we're okay to just do matches */
  543.   init_match(player, box, NOTYPE);
  544.   match_neighbor();
  545.   match_possession();
  546.   loc = match_result();
  547.   if (!GoodObject(loc))
  548.     return NOTHING;
  549.  
  550.   /* now we match on the contents */
  551.   init_match(loc, obj, NOTYPE);
  552.   match_possession();
  553.   return (match_result());
  554. }
  555.  
  556.  
  557. void page_return(player, target, type, message, def)
  558.      dbref player;
  559.      dbref target;
  560.      char *type;
  561.      char *message;
  562.      char *def;
  563.   /* code for auto-return page - HAVEN, IDLE, and AWAY messages */
  564.  
  565.   ATTR *d;
  566.   char *tbuf1 = NULL;
  567.   char tbuf2[BUFFER_LEN];
  568.   struct tm *ptr;
  569.   time_t t;
  570.  
  571.   if (message && *message) {
  572.     d = atr_get(target, message);
  573.     if (d) {
  574.       strcpy(tbuf2, uncompress(d -> value));
  575.       tbuf1 = exec(target, target, 0, tbuf2);
  576.       t = time(NULL);
  577.       ptr = (struct tm *) localtime(&t);
  578.       notify(player, tprintf("%s message from %s: %s", type,
  579.                  db[target].name, tbuf1));
  580.       if (tbuf1)
  581.     free(tbuf1);
  582. #ifdef MILITARY_TIME
  583.       notify(target, 
  584.          tprintf("[%d:%02d] %s message sent to %s.", 
  585.              ptr->tm_hour, ptr->tm_min, type, db[player].name));
  586. #else
  587.       notify(target, 
  588.          tprintf("[%d:%02d] %s message sent to %s.", 
  589.         ptr->tm_hour == 0 ? 12 : ptr->tm_hour > 12 ? (ptr->tm_hour - 12) :
  590.       ptr->tm_hour, ptr->tm_min, type, db[player].name));
  591. #endif                /* MILITARY_TIME */
  592.   } else if (def && *def)
  593.       notify(player, def);
  594.   }
  595. }
  596.  
  597. dbref where_is(thing)
  598.      dbref thing;
  599. {
  600.   /* returns "real" location of object. This is the location for players
  601.    * and things, source for exits, and NOTHING for rooms.
  602.    */
  603.  
  604.   if (!GoodObject(thing))
  605.     return NOTHING;
  606.   switch (Typeof(thing)) {
  607.   case TYPE_ROOM:
  608.     return NOTHING;
  609.   case TYPE_EXIT:
  610.     return Home(thing);
  611.   default:
  612.     return Location(thing);
  613.   }
  614. }
  615.  
  616. int nearby(obj1, obj2)
  617.   dbref obj1;
  618.   dbref obj2;
  619. {
  620.   /* returns 1 if obj1 is "nearby" object2. "Nearby" is defined as:  
  621.    *   obj1 is in the same room as obj2, obj1 is being carried by   
  622.    *   obj2, obj1 is carrying obj2. Returns 0 if object isn't nearby 
  623.    *   or the input is invalid.
  624.    */
  625.   dbref loc1, loc2;
  626.  
  627.   if (!GoodObject(obj1) || !GoodObject(obj2))
  628.     return 0;
  629.   loc1 = where_is(obj1);
  630.   if (loc1 == obj2)
  631.     return 1;
  632.   loc2 = where_is(obj2);
  633.   if ((loc2 == obj1) || (loc2 == loc1))
  634.     return 1;
  635.   return 0;
  636. }
  637.  
  638. void do_verb(player, cause, arg1, argv)
  639.      dbref player;
  640.      dbref cause;
  641.      char *arg1;
  642.      char *argv[];
  643. {
  644.   /* user-defined verbs */
  645.  
  646.   dbref victim;
  647.   dbref actor;
  648.   char *sptr[10];
  649.   int i;
  650.  
  651.   /* find the object that we want to read the attributes off
  652.    * (the object that was the victim of the command)
  653.    */
  654.  
  655.   /* our victim object can be anything */
  656.   init_match(player, arg1, NOTYPE);
  657.   match_everything();
  658.   victim = match_result();
  659.  
  660.   if (victim == NOTHING) {
  661.     notify(player, "What was the victim of the verb?");
  662.     return;
  663.   }
  664.  
  665.   /* find the object that executes the action */
  666.   init_match(player, argv[1], NOTYPE);
  667.   match_near_things();
  668.   actor = match_result();
  669.  
  670.   if (actor == NOTHING) {
  671.     notify(player, "What do you want to do the verb?");
  672.     return;
  673.   }
  674.  
  675.   /* Control check is fascist. 
  676.    * First check: we don't want <actor> to do something involuntarily.
  677.    *   Both victim and actor have to be controlled by the thing which did 
  678.    *   the @verb (for speed we do a WIZARD check first), or: cause controls
  679.    *   actor plus the second check is passed.
  680.    * Second check: we need read access to the attributes.
  681.    *   Either the player controls victim or the player
  682.    *   must be priviledged, or the victim has to be VISUAL.
  683.    */
  684.  
  685.   if (!(Wizard(player) || 
  686.     (controls(player, victim)  && controls(player, actor)) ||
  687.     ((controls(cause, actor) && Can_Examine(player, victim))))) {
  688.     notify(player, "Permission denied.");
  689.     return;
  690.   }
  691.  
  692.   /* we're okay. Now we copy our args into the stack, saving
  693.    * the old stack so we can restore it later.
  694.    */
  695.   
  696.   for (i = 0; i < 10; i++)
  697.     sptr[i] = wptr[i];
  698.  
  699.   for (i = 0; i < 10; i++)
  700.     wptr[i] = argv[i + 7];
  701.  
  702.   /* do the command, then restore the stack */
  703.  
  704.   did_it(actor, victim, 
  705.      upcasestr(argv[2]), argv[3], upcasestr(argv[4]), argv[5],
  706.      upcasestr(argv[6]), getloc(actor));
  707.  
  708.   for (i = 0; i < 10; i++)
  709.     wptr[i] = sptr[i];
  710.  
  711. }
  712.  
  713. char *grep_util(thing, pattern, lookfor, len)
  714.      dbref thing;
  715.      char *pattern;
  716.      char *lookfor;
  717.      int len;            /* strlen(lookfor) */
  718. {
  719.   /* returns a list of attributes which match <pattern> on <thing>
  720.    * whose contents have <lookfor>
  721.    */
  722.  
  723.   char *tbuf1;
  724.   char *s, *bp;
  725.   int found;
  726.   ALIST *a;
  727.  
  728.   tbuf1 = (char *) malloc(BUFFER_LEN + 1);
  729.  
  730.   bp = tbuf1;
  731.   for (a = db[thing].list; a; a = AL_NEXT(a)) {
  732.     if (!AL_BAD(a) && wild_match(pattern, AL_NAME(a))) {
  733.       s = (char *) uncompress(AL_STR(a));              /* warning: static */
  734.       found = 0;
  735.       while (*s && !found) {
  736.     if (!strncmp(lookfor, s, len))
  737.       found = 1;
  738.     else 
  739.       s++;
  740.       }
  741.       if (found) {
  742.     if (bp != tbuf1)
  743.       safe_chr(' ', tbuf1, &bp);
  744.     safe_str(AL_NAME(a), tbuf1, &bp);
  745.       }
  746.     }
  747.   }
  748.   *bp = '\0';
  749.   return tbuf1;
  750. }
  751.  
  752.  
  753. void do_grep(player, obj, lookfor, flag)
  754.      dbref player;
  755.      char *obj;
  756.      char *lookfor;               /* this is an UNPARSED arg */
  757.      int flag;            /* 0 for just list, 1 for hilites */
  758. {
  759.   dbref thing;
  760.   char *pattern;
  761.   int len, d, found, rlen;
  762.   ALIST *a;
  763.   char *s, *tp;
  764.   char tbuf1[BUFFER_LEN];
  765.   char repl[BUFFER_LEN];
  766.   
  767.   /* check this first */
  768.   if (flag && !ShowAnsi(player)) {
  769.     notify(player, "You must be set ANSI to use this option.");
  770.     return;
  771.   }
  772.   
  773.   if ((len = strlen(lookfor)) < 1) {
  774.     notify(player, "What pattern do you want to grep for?");
  775.     return;
  776.   }
  777.  
  778.   /* find the attribute pattern */
  779.   pattern = (char *) index(obj, '/');
  780.   if (!pattern)
  781.     pattern = (char *) "*";    /* set it to global match */
  782.   else
  783.     *pattern++ = '\0';
  784.  
  785.   /* now we've got the object. match for it. */
  786.   init_match(player, obj, NOTYPE);
  787.   match_everything();
  788.   thing = noisy_match_result();
  789.   if (thing == NOTHING)
  790.     return;
  791.   if (!Can_Examine(player, thing)) {
  792.     notify(player, "Permission denied.");
  793.     return;
  794.   }
  795.  
  796.   /* we can think of adding in the hilites like doing a find and replace */
  797.   sprintf(repl, "%s%s%s", ANSI_HILITE, lookfor, ANSI_NORMAL);
  798.   rlen = strlen(repl);
  799.  
  800.   if (flag) {
  801.     for (a = db[thing].list; a; a = AL_NEXT(a)) {
  802.       found = 0;
  803.       if (!AL_BAD(a) && wild_match(pattern, AL_NAME(a))) {
  804.     s = (char *) uncompress(AL_STR(a));              /* warning: static */
  805.     for (d = 0; (d < BUFFER_LEN) && *s; ) {
  806.       if (!strncmp(lookfor, s, len)) {
  807.         found = 1;
  808.         if ((d + rlen) < BUFFER_LEN) {
  809.           strcpy(tbuf1 + d, repl);
  810.           d += rlen;
  811.           s += len;
  812.         } else
  813.           tbuf1[d++] = *s++;
  814.       } else
  815.         tbuf1[d++] = *s++;
  816.     }
  817.     tbuf1[d++] = 0;
  818.       }
  819.       /* if we got it, display it */
  820.       if (found)
  821.     notify(player, tprintf("%s%s [#%d%s%s %s", 
  822.                    ANSI_HILITE, AL_NAME(a), Owner(AL_CREATOR(a)),
  823.                    (AL_FLAGS(a) & AF_LOCKED) ? "+]:" : "]:",
  824.                    ANSI_NORMAL, tbuf1));
  825.     }
  826.   } else {
  827.     notify(player, 
  828.       tprintf("The following attributes on %s have contents matching '%s':",
  829.           Name(thing), lookfor));
  830.     tp = grep_util(thing, pattern, lookfor, len);
  831.     notify(player, tp);
  832.     free(tp);
  833.   }
  834. }
  835.